home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / libg_261.zip / libg_261 / libg++ / src / Fix24.cc < prev    next >
C/C++ Source or Header  |  1994-08-12  |  8KB  |  330 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /* 
  3. Copyright (C) 1988 Free Software Foundation
  4.     written by Kurt Baudendistel (gt-eedsp!baud@gatech.edu)
  5.     adapted for libg++ by Doug Lea (dl@rocky.oswego.edu)
  6.  
  7. This file is part of the GNU C++ Library.  This library is free
  8. software; you can redistribute it and/or modify it under the terms of
  9. the GNU Library General Public License as published by the Free
  10. Software Foundation; either version 2 of the License, or (at your
  11. option) any later version.  This library is distributed in the hope
  12. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  13. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  14. PURPOSE.  See the GNU Library General Public License for more details.
  15. You should have received a copy of the GNU Library General Public
  16. License along with this library; if not, write to the Free Software
  17. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19.  
  20. //
  21. // Fix24.cc : fixed precision class support functions
  22. //
  23.  
  24. #ifdef __GNUG__
  25. #pragma implementation
  26. #endif
  27. #include <Fix24.h>
  28.  
  29. // basic operators too large to be inline
  30.  
  31. _G_int32_t Fix24::assign(double d) 
  32.   if (d == 1.0)
  33.     return Fix24_m_max;
  34.   else if (d > Fix24_max)
  35.   {
  36.     _G_int32_t i = Fix24_m_max;
  37.     range_error(i);
  38.     return i;
  39.   }
  40.   else if (d < Fix24_min)
  41.   {
  42.     _G_int32_t i = Fix24_m_min;
  43.     range_error(i);
  44.     return i;
  45.   }
  46.   else {
  47.     // Round to 24 bits
  48.     d = (_G_int32_t) (d * (1 << 24) + ((d >= 0)? 0.5 : -0.5));
  49.     /* Convert to integer format */
  50.     return ((_G_int32_t) d) << (Fix24_shift - 24);
  51.   }
  52. }
  53.  
  54. twolongs Fix48::assign(double d) 
  55.   if (d == 1.0)
  56.     return Fix48_m_max;
  57.   else if (d > Fix48_max)
  58.   {
  59.     twolongs i = Fix48_m_max;
  60.     range_error(i);
  61.     return i;
  62.   }
  63.   else if (d < Fix48_min)
  64.   {
  65.     twolongs i = Fix48_m_min;
  66.     range_error(i);
  67.     return i;
  68.   }
  69.   else {
  70.     twolongs i;
  71.     int sign = (d < 0);
  72.  
  73. /* First, convert the absolute value of d to a 48-bit integer format */
  74.     if (d < 0) d = -d;
  75.     i.u = ((_G_int32_t)(d *= Fix24_mult)) & 0xffffff00;
  76.     i.l = ((_G_uint32_t)((d - i.u)* (Fix24_mult / (1 << 7)))) & 0xffffff00;
  77.  
  78. /* Calculate the two's complement if d was negative */
  79.     if (sign) {
  80.     _G_uint32_t oldlower = i.l;
  81.     i.l = (~i.l + 1) & 0xffffff00;
  82.     i.u = (~i.u + (((oldlower ^ i.l) & Fix24_msb)? 0 : 1)) & ~0xffL;
  83.     }
  84.     return i;
  85.   }
  86. }
  87.  
  88.  
  89. Fix48 operator * (const Fix24& a, const Fix24& b)
  90. {
  91. // break a and b into lo and hi parts, and do a multiple-precision
  92. // multiply, with rounding
  93.  
  94.   int apos = (a.m >= 0);
  95.   _G_uint32_t ua = (apos)? a.m : - a.m;
  96.   ua <<= 1; // ua is biased so result will be 47 bit mantissa, not 46:
  97.   _G_uint32_t hi_a = (ua >> 16) & ((1 << 16) - 1);
  98.   _G_uint32_t lo_a = ua & ((1 << 16) - 1);
  99.  
  100.   int bpos = (b.m >= 0);
  101.   _G_uint32_t ub = (bpos)? b.m : -b.m;
  102.   _G_uint32_t hi_b = (ub >> 16) & ((1 << 16) - 1);
  103.   _G_uint32_t lo_b = ub & ((1 << 16) - 1);
  104.  
  105.   _G_uint32_t 
  106.     hi_r = hi_a * hi_b,
  107.     mi_r = hi_a * lo_b + lo_a * hi_b,
  108.     lo_r = lo_a * lo_b,
  109.     rl = ((hi_r << 16) & 0x00ffffffL) + (mi_r & 0x00ffffffL) + (lo_r >> 16);
  110.   twolongs r;
  111.   r.u = (hi_r & 0xffffff00L) + ((mi_r >> 16) & 0x0000ff00L)
  112.     + ((rl >> 16) & 0x0000ff00L);
  113.   r.l = rl << 8;
  114.  
  115.   if ( apos != bpos ) {
  116.     _G_uint32_t l = r.l;
  117.     r.l = -r.l;
  118.     r.u = (~r.u + ((l ^ r.l) & Fix24_msb ? 0 : Fix24_lsb)) & 0xffffff00;
  119.   }
  120.   return r;
  121. }
  122.  
  123. Fix24 operator / (const Fix24& a, const Fix24& b)
  124. {
  125.   _G_int32_t q;
  126.   int apos = (a.m >= 0);
  127.   _G_uint32_t la = (apos)? a.m : -a.m;
  128.   int bpos = (b.m >= 0);
  129.   _G_uint32_t lb = (bpos)? b.m: -b.m;
  130.   if (la >= lb)
  131.   {
  132.     q = (apos == bpos)? Fix24_m_max: Fix24_m_min;
  133.     a.range_error(q);
  134.   }
  135.   else                        // standard shift-based division alg
  136.   {
  137.     q = 0;
  138.     _G_int32_t r = la;
  139.  
  140.     for (int i = 32; i > 0; i--)
  141.     {
  142.     if ((unsigned)(r) > lb) {
  143.         q = (q << 1) | 1;
  144.         r -= lb;
  145.     }
  146.     else
  147.         q = (q << 1);
  148.     r <<= 1;
  149.     }
  150.  
  151.     q += 0x80;            // Round result to 24 bits
  152.     if (apos != bpos) q = -q;    // Fix sign
  153.   }
  154.   return (q & ~0xff);
  155. }
  156.  
  157.  
  158. Fix48 operator + (const Fix48&  f, const Fix48&  g)
  159. {
  160.   _G_int32_t lo_r = (f.m.l >> 8) + (g.m.l >> 8);
  161.   twolongs r;
  162.   r.u = f.m.u + g.m.u + (lo_r & 0x01000000L ? 0x00000100L : 0);
  163.   r.l =  lo_r << 8;
  164.  
  165.   if ( (f.m.u ^ r.u) & (g.m.u ^ r.u) & Fix24_msb )
  166.     f.overflow(r);
  167.   return r;
  168. }
  169.  
  170. Fix48 operator - (const Fix48&  f, const Fix48&  g)
  171. {
  172.   unsigned lo_r = (f.m.l >> 8) - (g.m.l >> 8);
  173.   twolongs r;
  174.   r.u = f.m.u - g.m.u - (lo_r & 0x01000000L ? 0x00000100L: 0);
  175.   r.l = lo_r << 8;
  176.  
  177.   if ( ((f.m.u ^ r.u) & (-g.m.u ^ r.u) & Fix24_msb) && g.m.u )
  178.     f.overflow(r);
  179.   return r;
  180. }
  181.  
  182. Fix48 operator * (const Fix48& a, int b)
  183. {
  184.   twolongs r;
  185.   int bpos = (b >= 0);
  186.   unsigned ub = (bpos)? b : -b;
  187.   if ( ub >= 65536L ) {
  188.     r = (bpos)? Fix48_m_max : Fix48_m_min;
  189.     a.range_error(r);
  190.   }
  191.   else {
  192.     _G_uint32_t 
  193.       lo_r = (a.m.l & 0xffff) * ub,
  194.       mi_r = ((a.m.l >> 16) & 0xffff) * ub,
  195.       hi_r = a.m.u * ub;
  196.     r.l = lo_r + (mi_r << 16);
  197.     r.u = hi_r + ((mi_r >> 8) & 0x00ffff00L);
  198.     if ( !bpos ) {
  199.       _G_uint32_t l = r.l;
  200.       r.l = -r.l & 0xffffffff;
  201.       r.u = ~r.u + ((l ^ r.l) & Fix24_msb ? 0 : Fix24_lsb);
  202.     }
  203.   }
  204.   return r;
  205. }
  206.  
  207. Fix48 operator << (const Fix48& a, int b)
  208. {
  209.   twolongs r; r.u = 0; r.l = 0;
  210.   if ( b >= 0 )
  211.     if ( b < 24 ) {
  212.       r.u = (a.m.u << b) + ((a.m.l >> (24 - b)) & 0xffffff00L);
  213.       r.l = a.m.l << b;
  214.     }
  215.     else if ( b < 48 ) {
  216.       r.u = a.m.l << (b - 24);
  217.     }
  218.   return r;
  219. }
  220.  
  221. Fix48 operator >> (const Fix48& a, int b)
  222. {
  223.   twolongs r; r.u = 0; r.l = 0;
  224.   if ( b >= 0 )
  225.     if ( b < 24 ) {
  226.       r.l = ((a.m.u << (24 - b)) & 0xffffffffL) + ((a.m.l >> b) & 0xffffff00L);
  227.       r.u = (a.m.u >> b) & ~0xffL;
  228.     }
  229.     else if ( b < 48 ) {
  230.       r.l = (a.m.u >> (b - 24)) & 0xffffff00L;
  231.       r.u = (a.m.u >> 24) & ~0xffL;
  232.     }
  233.     else {
  234.       r.l = (a.m.u >> 24) & ~0xffL;
  235.       r.u = r.l;
  236.     }
  237.   return r;
  238. }
  239.  
  240. // error handling
  241.  
  242. void Fix24::overflow(_G_int32_t& i) const
  243. {
  244.   (*Fix24_overflow_handler)(i);
  245. }
  246.  
  247. void Fix48::overflow(twolongs& i) const
  248. {
  249.   (*Fix48_overflow_handler)(i);
  250. }
  251.  
  252. void Fix24::range_error(_G_int32_t& i) const
  253. {
  254.   (*Fix24_range_error_handler)(i);
  255. }
  256.  
  257. void Fix48::range_error(twolongs& i) const
  258. {
  259.   (*Fix48_range_error_handler)(i);
  260. }
  261.  
  262. // data definitions
  263.  
  264. Fix24_peh Fix24_overflow_handler = Fix24_overflow_saturate;
  265. Fix48_peh Fix48_overflow_handler = Fix48_overflow_saturate;
  266.  
  267. Fix24_peh Fix24_range_error_handler = Fix24_warning;
  268. Fix48_peh Fix48_range_error_handler = Fix48_warning;
  269.  
  270. //function definitions
  271.  
  272. Fix24_peh set_Fix24_overflow_handler(Fix24_peh new_handler) {
  273.   Fix24_peh old_handler = Fix24_overflow_handler;
  274.   Fix24_overflow_handler = new_handler;
  275.   return old_handler;
  276. }
  277.  
  278. Fix48_peh set_Fix48_overflow_handler(Fix48_peh new_handler) {
  279.   Fix48_peh old_handler = Fix48_overflow_handler;
  280.   Fix48_overflow_handler = new_handler;
  281.   return old_handler;
  282. }
  283.  
  284. void set_overflow_handler(Fix24_peh handler24, Fix48_peh handler48) {
  285.   set_Fix24_overflow_handler(handler24);
  286.   set_Fix48_overflow_handler(handler48);
  287. }
  288.  
  289. Fix24_peh set_Fix24_range_error_handler(Fix24_peh new_handler) {
  290.   Fix24_peh old_handler = Fix24_range_error_handler;
  291.   Fix24_range_error_handler = new_handler;
  292.   return old_handler;
  293. }
  294.  
  295. Fix48_peh set_Fix48_range_error_handler(Fix48_peh new_handler) {
  296.   Fix48_peh old_handler = Fix48_range_error_handler;
  297.   Fix48_range_error_handler = new_handler;
  298.   return old_handler;
  299. }
  300.  
  301. void set_range_error_handler(Fix24_peh handler24, Fix48_peh handler48) {
  302.   set_Fix24_range_error_handler(handler24);
  303.   set_Fix48_range_error_handler(handler48);
  304. }
  305.  
  306. void Fix24_overflow_saturate(_G_int32_t& i)
  307.   { i = (i > 0 ? Fix24_m_min : Fix24_m_max); }
  308. void Fix24_ignore(_G_int32_t&) {}
  309. void Fix24_warning(_G_int32_t&)
  310.   { cerr << "warning: Fix24 result out of range\n"; }
  311. void Fix24_overflow_warning_saturate(_G_int32_t& i)
  312.   { cerr << "warning: Fix24 result out of range\n"; 
  313.    Fix24_overflow_saturate(i); }
  314. void Fix24_abort(_G_int32_t&)
  315.   { cerr << "error: Fix24 result out of range\n"; abort(); }
  316.  
  317. void Fix48_ignore(twolongs&) {}
  318. void Fix48_overflow_saturate(twolongs& i)
  319.   { i = (i.u > 0 ? Fix48_m_min : Fix48_m_max); }
  320. void Fix48_warning(twolongs&)
  321.   { cerr << "warning: Fix48 result out of range\n"; }
  322. void Fix48_overflow_warning_saturate(twolongs& i)
  323.   { cerr << "warning: Fix48 result out of range\n"; 
  324.    Fix48_overflow_saturate(i); }
  325. void Fix48_abort(twolongs&)
  326.   { cerr << "error: Fix48 result out of range\n"; abort(); }
  327.  
  328.